/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
/* $Id: tty.c 3 2007-07-10 06:59:05Z kf701.ye $ */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>

#include "factory.h"

/**
 * @brief set tty speed
 * @param fd from open tty
 * @param speed 115200,38400,9600...
 */
bool set_speed(int fd, int speed)
{
	speed_t speed_arr[] = { B230400, B115200, B57600, B38400, B19200, 
		B9600, B4800, B2400, B1200, B300, };
	int name_arr[] = { 230400, 115200, 57600, 38400, 19200, 
		9600, 4800, 2400, 1200, 300, };

	int i;
	int status;
	struct termios Opt;
	tcgetattr(fd, &Opt);
	for ( i= 0; i < sizeof(speed_arr)/sizeof(int); i++ ) 
	{
		if (speed == name_arr[i]) 
		{
			tcflush(fd, TCIOFLUSH);
			cfsetispeed(&Opt, speed_arr[i]);
			cfsetospeed(&Opt, speed_arr[i]);
			status = tcsetattr(fd, TCSANOW, &Opt);
			if (status != 0) 
			{
				sys_message("%s,%d: tcsetattr error\n",__FILE__,__LINE__);
				return false;
			}
			tcflush(fd,TCIOFLUSH);
		}
	}
	return true;
}

/**
 * @brief set tty databit stopbit and parity
 * @param fd from open tty
 * @param databits 7 or 8
 * @param stopbits 1 or 2
 * @param parity N,E,O,S
 */
bool set_parity(int fd,int databits,int stopbits,int parity)
{
	struct termios options;
	if ( tcgetattr( fd,&options) != 0) 
	{
		sys_message("%s,%d: SetupSerial error\n",__FILE__,__LINE__);
		return false;
	}
	options.c_cflag &= ~CSIZE;
	switch (databits)
	{
		case 7:
			options.c_cflag |= CS7;
			break;
		case 8:
			options.c_cflag |= CS8;
			break;
		default:
			sys_message("%s,%d: Unsupported data size\n",__FILE__,__LINE__);
			return false;
	}
	switch (parity)
	{
		case 'n':
		case 'N':
			options.c_cflag &= ~PARENB; /* Clear parity enable */
			options.c_iflag &= ~INPCK; /* Enable parity checking */
			break;
		case 'o':
		case 'O':
			options.c_cflag |= (PARODD | PARENB); /* set odd */
			options.c_iflag |= INPCK; /* Disnable parity checking */
			break;
		case 'e':
		case 'E':
			options.c_cflag |= PARENB; /* Enable parity */
			options.c_cflag &= ~PARODD; /* convert to enev */
			options.c_iflag |= INPCK; /* Disnable parity checking */
			break;
		case 'S':
		case 's': /*as no parity*/
			options.c_cflag &= ~PARENB;
			options.c_cflag &= ~CSTOPB;
			break;
		default:
			sys_message("%s,%d: Unsupported parity\n",__FILE__,__LINE__);
			return false;
	}
	/* set stopbit */
	switch (stopbits)
	{
		case 1:
			options.c_cflag &= ~CSTOPB;
			break;
		case 2:
			options.c_cflag |= CSTOPB;
			break;
		default:
			sys_message("%s,%d: Unsupported stop bits\n",__FILE__,__LINE__);
			return false;
	}
	/* Set input parity option */
	if (parity != 'n')
		options.c_iflag |= INPCK;
	tcflush(fd,TCIFLUSH);
	options.c_cc[VTIME] = 150; /* set time out 15 seconds*/
	options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
	if (tcsetattr(fd,TCSANOW,&options) != 0)
	{
		sys_message("%s,%d: SetupSerial error\n",__FILE__,__LINE__);
		return false;
	}
	return true;
}
